#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <gmp.h>
#include <pthread.h>

#define ITER 250000000 //Numero de pontos aleatorio gerados por cada thread
#define N_THREADS 4 //Numero de threads a serem executadas

typedef struct
{
   long id;
} ThreadData;

long *pt_I;
long *pt_T;

void *f_generatePoints(void *arg)
{
	double x, y;
	struct drand48_data randBuffer;
	srand48_r(time(NULL), &randBuffer);
	long j;
	ThreadData* data = (ThreadData*) arg;
	for (j = 0 ; j < ITER ; j++) 
	{
		drand48_r(&randBuffer, &x);
		drand48_r(&randBuffer, &y);
		if((x*x + y*y) <= 1.0)		
		{
			pt_I[data->id]++;
			pt_T[data->id]++;
		}
		else
		{
			pt_T[data->id]++;
		}			
	}
}

int main (int argc, char *argv[]) 
{
	mpf_t pi;
	mpf_t pointsIn;
	mpf_t pointsTotal;
	pthread_t *thread_generatePoints = (pthread_t*) malloc (N_THREADS * sizeof(pthread_t));
	time_t begin, end;
	double time_spent;
	long i;
	
	FILE *piFile = fopen("out_monteCarloPar.txt","w+");

	if(piFile == NULL) 
	{
		return EXIT_FAILURE;
	}
	
	//Setar precisão (usar todas as 10 milhões de casas) e inicializar variaveis do metodo
	mpf_set_default_prec(40000000);
	mpf_init(pi);
	mpf_init(pointsIn);
	mpf_init(pointsTotal);
	
	pt_I = (long*) malloc (N_THREADS * sizeof(long));
	pt_T = (long*) malloc (N_THREADS * sizeof(long));
	
	printf("Starting...");
	printf("\n");
	time(&begin);
	
	for (i = 0 ; i < N_THREADS ; i++) 
	{
		ThreadData* td = malloc(sizeof(ThreadData));
		td->id = i;
		pthread_create(&thread_generatePoints[i], NULL, f_generatePoints, td);
	}
	for (i = 0 ; i < N_THREADS ; i++) 
	{
		pthread_join(thread_generatePoints[i], NULL);
		mpf_add_ui(pointsIn, pointsIn, pt_I[i]);
		mpf_add_ui(pointsTotal, pointsTotal, pt_T[i]);
	}
	
	mpf_div(pi, pointsIn, pointsTotal); 
	mpf_mul_ui(pi,pi,4); // pi = 4*pontosDentro/pontosTotal 
	
	time(&end);
	time_spent = difftime(end, begin);

	mpf_out_str(piFile,10,250000,pi);
	fprintf(piFile,"\n");

	printf("Time: %lf - Number of Points: %ld\n",time_spent,(long)(ITER*N_THREADS));

	fclose(piFile);

	return 0;
}
